polymorphism: better names for .binaryValue and .booleanValue are .asInteger and...
[supercollider.git] / Help / Other Topics / MultiChannel.html
blob5c190be1ebee6dbcc31ca49f60f87dd424fc07fc
1 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
2 <html>
3 <head>
4 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
5 <meta http-equiv="Content-Style-Type" content="text/css">
6 <title></title>
7 <meta name="Generator" content="Cocoa HTML Writer">
8 <meta name="CocoaVersion" content="824.42">
9 <style type="text/css">
10 p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 18.0px Helvetica}
11 p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px}
12 p.p3 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica}
13 p.p4 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco; color: #a71e12; min-height: 12.0px}
14 p.p5 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco}
15 p.p6 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco; color: #a71e12}
16 p.p7 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco; min-height: 12.0px}
17 p.p8 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Monaco; min-height: 16.0px}
18 p.p9 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco; color: #0019b7}
19 p.p10 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco; color: #606060}
20 span.s1 {color: #0019b7}
21 span.s2 {color: #a71e12}
22 span.s3 {color: #000000}
23 span.s4 {font: 9.0px Helvetica}
24 span.s5 {color: #606060}
25 span.s6 {color: #326f17}
26 span.Apple-tab-span {white-space:pre}
27 </style>
28 </head>
29 <body>
30 <p class="p1"><b>Multichannel Expansion</b></p>
31 <p class="p2"><br></p>
32 <p class="p3">Multiple channels of audio are represented as Arrays.</p>
33 <p class="p4"><br></p>
34 <p class="p5">s.boot;</p>
35 <p class="p6">// one channel</p>
36 <p class="p5">{ <span class="s1">Blip</span>.ar(800,4,0.1) }.play;</p>
37 <p class="p7"><br></p>
38 <p class="p6">// two channels</p>
39 <p class="p5">{ [ <span class="s1">Blip</span>.ar(800,4,0.1), <span class="s1">WhiteNoise</span>.ar(0.1) ] }.play;</p>
40 <p class="p8"><br></p>
41 <p class="p3">Each channel of output will go out a different speaker, so your limit here is two for a stereo output. If you have a supported multi channel audio interface or card then you can output as many channels as the card supports.</p>
42 <p class="p2"><br></p>
43 <p class="p3">All UGens have only a single output. This uniformity facilitates the use of array operations to perform manipulation of multi channel structures.</p>
44 <p class="p2"><br></p>
45 <p class="p3">In order to implement multichannel output, UGens create a separate UGen known as an <b>OutputProxy</b> for each output. An OutputProxy is just a place holder for the output of a multichannel UGen. OutputProxies are created internally, you never need to create them yourself, but it is good to be aware that they exist so you'll know what they are when you run across them.</p>
46 <p class="p2"><br></p>
47 <p class="p6">// look at the outputs of Pan2:</p>
48 <p class="p5"><span class="s1">Pan2</span>.ar(<span class="s1">PinkNoise</span>.ar(0.1), <span class="s1">FSinOsc</span>.kr(3)).dump;</p>
49 <p class="p7"><br></p>
50 <p class="p5">play({ <span class="s1">Pan2</span>.ar(<span class="s1">PinkNoise</span>.ar(0.1), <span class="s1">FSinOsc</span>.kr(1)); });</p>
51 <p class="p2"><br></p>
52 <p class="p3">When an <b>Array</b> is given as an input to a unit generator it causes an array of multiple copies of that unit generator to be made, each with a different value from the input array. This is called multichannel expansion. All but a few special unit generators perform multichannel expansion. Only Arrays are expanded, no other type of Collection, not even subclasses of Array.</p>
53 <p class="p8"><br></p>
54 <p class="p5">{ <span class="s1">Blip</span>.ar(500,8,0.1) }.play <span class="s2">// one channel</span></p>
55 <p class="p7"><br></p>
56 <p class="p6">// the array in the freq input causes an Array of 2 Blips to be created :</p>
57 <p class="p5">{ <span class="s1">Blip</span>.ar([499,600],8,0.1) }.play <span class="s2">// two channels</span></p>
58 <p class="p7"><br></p>
59 <p class="p6"><span class="s1">Blip</span><span class="s3">.ar(500,8,0.1).postln </span>// one unit generator created.</p>
60 <p class="p7"><br></p>
61 <p class="p6"><span class="s1">Blip</span><span class="s3">.ar([500,601],8,0.1).postln </span>// two unit generators created.</p>
62 <p class="p8"><br></p>
63 <p class="p3">Multichannel expansion will propagate through the expression graph. When a unit generator constructor is called with an array of inputs, it returns an array of instances. If that array is the input to another constructor, then another array is created, and so on.</p>
64 <p class="p2"><br></p>
65 <p class="p5">{ <span class="s1">RLPF</span>.ar(<span class="s1">Saw</span>.ar([100,250],0.05), <span class="s1">XLine</span>.kr(8000,400,5), 0.05) }.play;</p>
66 <p class="p7"><br></p>
67 <p class="p6">// the [100,250] array of frequency inputs to Saw causes Saw.ar to return<span class="Apple-converted-space"> </span></p>
68 <p class="p6">// an array of two Saws, that array causes RLPF.ar to create two RLPFs.</p>
69 <p class="p6">// Both RLPFs share a single instance of XLine.</p>
70 <p class="p8"><br></p>
71 <p class="p3">When a constructor is parameterized by two or more arrays, then the number of channels created is equal to the longest array, with parameters being pulled from each array in parallel. The shorter arrays will wrap.</p>
72 <p class="p2"><br></p>
73 <p class="p3">for example, the following:</p>
74 <p class="p8"><br></p>
75 <p class="p5"><span class="s1">Pulse</span>.ar([400, 500, 600],[0.5, 0.1], 0.2)</p>
76 <p class="p8"><br></p>
77 <p class="p3">is equivalent to:</p>
78 <p class="p8"><br></p>
79 <p class="p5">[ <span class="s1">Pulse</span>.ar(400,0.5,0.2), <span class="s1">Pulse</span>.ar(500,0.1,0.2), <span class="s1">Pulse</span>.ar(600,0.5,0.2) ]</p>
80 <p class="p8"><br></p>
81 <p class="p3">A more complex example based on the Saw example above is given below. In this example, the XLine is expanded to two instances, one going from 8000 Hz to 400 Hz and the other going in the opposite direction from 500 Hz to 7000 Hz. These two XLines are 'married' to the two Saw oscillators and used to parameterize two copies of RLPF. So on the left channel a 100 Hz Saw is filtered from 8000 Hz to 400 Hz and on the right channel a 250 Hz Saw is filtered from 500 Hz to 7000 Hz.</p>
82 <p class="p8"><br></p>
83 <p class="p5">{ <span class="s1">RLPF</span>.ar(<span class="s1">Saw</span>.ar([100,250],0.05), <span class="s1">XLine</span>.kr([8000,500],[400,7000],5), 0.05) }.play;</p>
84 <p class="p8"><br></p>
85 <p class="p3"><b>Protecting arrays against expansion</b></p>
86 <p class="p3">Some unit generators such as <b>Klank</b> require arrays of values as inputs. Since all arrays are expanded, you need to protect some arrays by a <b>Ref</b> object. A Ref instance is an object with a single slot named 'value' that serves as a holder of an object. Ref.new(object) one way to create a Ref, but there is a syntactic shortcut. The backquote ` is a unary operator that is equivalent to calling Ref.new(something). So to protect arrays that are inputs to a Klank or similar UGens you write:</p>
87 <p class="p2"><br></p>
88 <p class="p5"><span class="s1">Klank</span>.ar(`[[400,500,600],[1,2,1]], z)</p>
89 <p class="p2"><br></p>
90 <p class="p3">You can still create multiple Klanks by giving it an array of Ref'ed arrays.</p>
91 <p class="p2"><br></p>
92 <p class="p5"><span class="s1">Klank</span>.ar([ `[[400,500,600],[1,2,1]],<span class="Apple-converted-space">  </span>`[[700,800,900],[1,2,1]] ], z)</p>
93 <p class="p2"><br></p>
94 <p class="p3">is equivalent to:</p>
95 <p class="p2"><br></p>
96 <p class="p5"><span class="s4">[ </span><span class="s1">Klank</span>.ar(`[[400,500,600],[1,2,1]], z),<span class="Apple-converted-space">  </span><span class="s1">Klank</span>.ar(`[[700,800,900],[1,2,1]], z)]</p>
97 <p class="p2"><br></p>
98 <p class="p3"><b>Reducing channel expansion with Mix</b></p>
99 <p class="p3">The <b>Mix</b> object provides the means for reducing multichannel arrays to a single channel.</p>
100 <p class="p2"><br></p>
101 <p class="p6"><span class="s1">Mix</span><span class="s3">.new([a, b, c]) </span>// array of channels</p>
102 <p class="p8"><br></p>
103 <p class="p3">is equivalent to:</p>
104 <p class="p8"><br></p>
105 <p class="p6"><span class="s3">a + b + c<span class="Apple-converted-space">  </span></span>// mixed to one</p>
106 <p class="p8"><br></p>
107 <p class="p3">Mix is more efficient than using + since it can perform multiple additions at a time. But the main advantage is that it can deal with situations where the number of channels is arbitrary or determined at runtime.</p>
108 <p class="p2"><br></p>
109 <p class="p6">// three channels of Pulse are mixed to one channel</p>
110 <p class="p5">{ <span class="s1">Mix</span>.new(<span class="Apple-converted-space">  </span><span class="s1">Pulse</span>.ar([400, 501, 600], [0.5, 0.1], 0.1) ) }.play</p>
111 <p class="p2"><br></p>
112 <p class="p3">Multi channel expansion works differently for Mix. Mix takes one input which is an array (one not protected by a Ref). That array does not cause copies of Mix to be made. All elements of the array are mixed together in a single Mix object. On the other hand if the array contains one or more arrays then multi channel expansion is<span class="Apple-converted-space"> </span></p>
113 <p class="p3">performed one level down. This allows you to mix an array of stereo (two element) arrays resulting in one two channel array. For example:</p>
114 <p class="p2"><br></p>
115 <p class="p6"><span class="s1">Mix</span><span class="s3">.new( [ [a, b], [c, d], [e, f] ] ) </span>// input is an array of stereo pairs</p>
116 <p class="p2"><br></p>
117 <p class="p3">is equivalent to:</p>
118 <p class="p2"><br></p>
119 <p class="p6">// mixed to a single stereo pair</p>
120 <p class="p5">[ <span class="s1">Mix</span>.new( [a, c, e] ), <span class="s1">Mix</span>.new( [b, d, f] ) ]<span class="Apple-converted-space"> </span></p>
121 <p class="p2"><br></p>
122 <p class="p3">Currently it is not recursive. You cannot use Mix on arrays of arrays of arrays.</p>
123 <p class="p2"><br></p>
124 <p class="p3">Here's a final example illustrating multi channel expansion and Mix. By changing the variable 'n' you can change the number of voices in the patch. How many voices can your machine handle?</p>
125 <p class="p2"><br></p>
126 <p class="p5">(</p>
127 <p class="p5">{</p>
128 <p class="p5"><span class="Apple-tab-span"> </span><span class="s1">var</span> n;</p>
129 <p class="p6"><span class="s3"><span class="Apple-tab-span"> </span>n = 8; </span>// number of 'voices'</p>
130 <p class="p6"><span class="s3"><span class="Apple-tab-span"> </span></span><span class="s1">Mix</span><span class="s3">.new( </span>// mix all stereo pairs down.</p>
131 <p class="p6"><span class="s3"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span></span><span class="s1">Pan2</span><span class="s3">.ar( </span>// pan the voice to a stereo position</p>
132 <p class="p6"><span class="s3"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span></span><span class="s1">CombL</span><span class="s3">.ar( </span>// a comb filter used as a string resonator</p>
133 <p class="p6"><span class="s3"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span></span><span class="s1">Dust</span><span class="s3">.ar( </span>// random impulses as an excitation function</p>
134 <p class="p6"><span class="s3"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span></span>// an array to cause expansion of Dust to n channels</p>
135 <p class="p6"><span class="s3"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span></span>// 1 means one impulse per second on average</p>
136 <p class="p5"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="s1">Array</span>.fill(n, 1),<span class="Apple-converted-space"> </span></p>
137 <p class="p6"><span class="s3"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>0.3 </span>// amplitude</p>
138 <p class="p5"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>),<span class="Apple-converted-space"> </span></p>
139 <p class="p6"><span class="s3"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>0.01, </span>// max delay time in seconds</p>
140 <p class="p6"><span class="s3"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span></span>// array of different random lengths for each 'string'</p>
141 <p class="p5"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="s1">Array</span>.fill(n, {0.004.rand+0.0003}),<span class="Apple-converted-space"> </span></p>
142 <p class="p6"><span class="s3"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>4 </span>// decay time in seconds</p>
143 <p class="p5"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>),</p>
144 <p class="p6"><span class="s3"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span></span><span class="s1">Array</span><span class="s3">.fill(n,{1.0.rand2}) </span>// give each voice a different pan position</p>
145 <p class="p5"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>)</p>
146 <p class="p5"><span class="Apple-tab-span"> </span>)</p>
147 <p class="p5">}.play;</p>
148 <p class="p5">)</p>
149 <p class="p7"><br></p>
150 <p class="p7"><br></p>
151 <p class="p3"><b>Using flop for multichannel expansion</b></p>
152 <p class="p3">The method <i>flop</i> swaps columns and rows, allowing to derive series of argument sets:</p>
153 <p class="p7"><br></p>
154 <p class="p5">(</p>
155 <p class="p9">SynthDef<span class="s3">(</span><span class="s5">"help_multichannel"</span><span class="s3">, { </span>|out=0, freq=440, mod=0.1, modrange=20|</p>
156 <p class="p5"><span class="Apple-tab-span"> </span><span class="s1">Out</span>.ar(out,</p>
157 <p class="p5"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="s1">SinOsc</span>.ar(</p>
158 <p class="p5"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="s1">LFPar</span>.kr(mod, 0, modrange) + freq</p>
159 <p class="p5"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>) * <span class="s1">EnvGate</span>(0.1)</p>
160 <p class="p5"><span class="Apple-tab-span"> </span>)</p>
161 <p class="p5">}).send(s);</p>
162 <p class="p5">)</p>
163 <p class="p7"><br></p>
164 <p class="p5">(</p>
165 <p class="p5"><span class="s1">var</span> freq, mod, modrange;</p>
166 <p class="p7"><br></p>
167 <p class="p5">freq = <span class="s1">Array</span>.exprand(8, 400, 5000);</p>
168 <p class="p5">mod = <span class="s1">Array</span>.exprand(8, 0.1, 2);</p>
169 <p class="p5">modrange = <span class="s1">Array</span>.rand(8, 0.1, 40);</p>
170 <p class="p7"><br></p>
171 <p class="p5">fork {</p>
172 <p class="p5"><span class="Apple-tab-span"> </span>[<span class="s6">\freq</span>, freq, <span class="s6">\mod</span>, mod, <span class="s6">\modrange</span>, modrange].flop.do { <span class="s1">|args|</span></p>
173 <p class="p5"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>args.postln;</p>
174 <p class="p10"><span class="s3"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span></span><span class="s1">Synth</span><span class="s3">(</span>"help_multichannel"<span class="s3">, args);</span></p>
175 <p class="p5"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>0.3.wait;</p>
176 <p class="p5"><span class="Apple-tab-span"> </span>}</p>
177 <p class="p5">};</p>
178 <p class="p5">)</p>
179 <p class="p7"><br></p>
180 <p class="p7"><span class="Apple-tab-span"> </span></p>
181 <p class="p7"><br></p>
182 <p class="p3">Similarly, <b>Function-flop</b> returns an unevaluated function that will expand to its arguments when evaluated:</p>
183 <p class="p7"><br></p>
184 <p class="p5">(</p>
185 <p class="p5"><span class="s1">SynthDef</span>(<span class="s5">"blip"</span>, { <span class="s1">|freq|</span> <span class="s1">Out</span>.ar(0, <span class="s1">Line</span>.ar(0.1, 0, 0.05, 1, 0, 2)<span class="Apple-converted-space"> </span></p>
186 <p class="p5"><span class="Apple-tab-span"> </span>* <span class="s1">Pulse</span>.ar(freq * [1, 1.02])) }).send(s);</p>
187 <p class="p7"><br></p>
188 <p class="p9"><span class="s3">a = { </span>|dur=1, x=1, n=10, freq=400|</p>
189 <p class="p5"><span class="Apple-tab-span"> </span>fork { n.do {</p>
190 <p class="p5"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>if(x.coin) { <span class="s1">Synth</span>(<span class="s5">"blip"</span>, [<span class="s6">\freq</span>, freq]) };</p>
191 <p class="p5"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>(dur / n).wait;</p>
192 <p class="p5"><span class="Apple-tab-span"> </span>} }</p>
193 <p class="p5">}.flop;</p>
194 <p class="p5">)</p>
195 <p class="p7"><br></p>
196 <p class="p5">a.value(5, [0.3, 0.3, 0.2], [12, 32, 64], [1000, 710, 700]);</p>
197 <p class="p7"><br></p>
198 <p class="p8"><br></p>
199 <p class="p8"><br></p>
200 <p class="p8"><br></p>
201 </body>
202 </html>